package org.pybaldaj.bot;

import java.util.Collection;
import java.util.LinkedList;
import java.util.SortedSet;
import java.util.TreeSet;

import org.pybaldaj.IField;
import org.pybaldaj.Move;

public class Bot {

	public void doOptimalMove(IField f, Iterable<String> words) {
		Move move = findOptimalMove(f, words);
		doMove(f, move);
	}
	
	public void doMove(IField f, Move move) {
		f.setChar(move.getCellId(), move.getCharacter());
	}
	
	public Move findOptimalMove(IField f, Iterable<String> words) {
		
		int optPoints = -1;
		Move optMove = null;
		
		Collection<Move> moves = findMoves(f, words);
		for (Move move : moves) {
			if (optPoints < move.getPoints()) {
				optMove = move;
				optPoints = move.getPoints();
			}
		}
		if (null == optMove) {
			throw new RuntimeException("no moves!");
		}
		return optMove;
	}
	
	public Iterable<String> getAvailableKeys(IField f) {
		SortedSet<String> res = new TreeSet<String>();
		
		Collection<int[]> pathes = new LinkedList<int[]>();
		findWordOnField(f, "????", false, pathes);
		for (int[] is : pathes) {
			StringBuilder sb = new StringBuilder();
			for (int i : is) {
				sb.append(f.getChar(i) == '\0' ? '?' : f.getChar(i));
			}
			String key = sb.toString();
			int pos = key.indexOf('?');
			if (pos < 0) {
				res.add(key);
			} else {
				for (char subst = 'А'; subst < 'Я'; subst++) {
					res.add(key.replace('?', subst));
				}
			}
		}
		return res;
	}


	
	/**
	 * 
	 * @param f
	 * @param words
	 */
	public Collection<Move> findMoves(IField f, Iterable<String> words) {
		Collection<Move> moves = new LinkedList<Move>();
		
		try {
			
			for (String word: words) {
				
				Collection<int[]> pathes = new LinkedList<int[]>();
				
				
				// no duplicates
				if (findWordOnField(f, word, true, pathes)) {
					continue;
				}
				pathes = new LinkedList<int[]>();
				
				findWordOnField(f, word, false, pathes);
				
				if (!pathes.isEmpty()) {

					// check if there was used blank cell, otherwise - skip
					for (int[] path : pathes) {
						
						int blankId = -1;
						for (int i = 0; i < path.length; i++) {
							if (f.getChar(path[i]) == '\0') {
								blankId = i;
								break;
							}
						}
						if (blankId != -1) {
							moves.add(new Move(path[blankId], word.charAt(blankId), word, (byte)word.length()));
						}
						
					}
					
					
					
					
					
				}
			}
			return moves;
		} catch (Exception e) {// Catch exception if any
			// FIXME exceptions
			throw new RuntimeException(e);
		}
	}
	

	/**
	 * 
	 * @param f
	 * @param word
	 * @param emptyCellUsed
	 * @param pathes OUT parameter
	 */
	public boolean findWordOnField(IField f, String word, boolean emptyCellUsed, Collection<int[]> pathes) {
		
		int s = f.getCells().size();
		
		for (int i = 0; i < s; i++) {
			if (('?' == word.charAt(0) && f.getChar(i) != '\0') ||
						(Character.toLowerCase(f.getChar(i)) == Character.toLowerCase(word.charAt(0)))
					) {
				int[] curPath = new int[word.length()];
				curPath[0] = i;
				findWordOnField(f, word.substring(1), i, emptyCellUsed, curPath, (byte)1, pathes);
				curPath[0]=-1;
			} else if (!emptyCellUsed && f.getChar(i) == '\0') {
				int[] curPath = new int[word.length()];
				curPath[0] = i;
				findWordOnField(f, word.substring(1), i, true, curPath, (byte)1, pathes);
				curPath[0]=-1;
			} else {
				continue;
			}
		}
		return !pathes.isEmpty();
		
	}
	
	private void findWordOnField(IField f, String word, Integer startCellId, boolean emptyCellUsed, int[] curPath, byte idx, Collection<int[]> pathes) {
		
		if (word.isEmpty()) {
			pathes.add((int[]) curPath.clone());
			return;
		}
		
		Collection<Integer> neighbours = f.getCellNeighbours(startCellId);

		for (Integer i : neighbours) {
			boolean contains= false;
			for (byte b = 0; b < idx; b++) {
				if (curPath[b] == i) {
					contains = true;
				}
			}
			if (contains) {
				continue;
			}
			
			if (('?' == word.charAt(0) && f.getChar(i) != '\0') ||
						(Character.toLowerCase(f.getChar(i)) == Character.toLowerCase(word.charAt(0)))
					) {
				curPath[idx] = i;
				findWordOnField(f, word.substring(1), i, emptyCellUsed, curPath, (byte) (idx + 1), pathes);
				curPath[idx] = -1;
			} else if (!emptyCellUsed && f.getChar(i) == '\0') {
				curPath[idx] = i;
				findWordOnField(f, word.substring(1), i, true, curPath, (byte) (idx + 1), pathes);
				curPath[idx] = -1;
			} else {
				continue;
			}
		}
	}
}
